﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Kokomo.Mirror.PeFormat.Symbols;

namespace Kokomo.Mirror.PeFormat
{
	public static class DebugHelper
	{
		[DllImport(DllImports.DebugHelp, CharSet = CharSet.Unicode)]
		public static extern int UnDecorateSymbolName(
		  string DecoratedName,
		  StringBuilder UnDecoratedName,
		  int UndecoratedLength,
		  UndecorateOptions Flags
		);
		//[DllImport(DbgHelpDll, SetLastError = true, CharSet = CharSet.Ansi)]
		//// SymInitializeA is supported by older versions
		//internal static extern bool SymInitialize(
		//  IntPtr hProcess,
		//  string UserSearchPath,
		//  bool fInvadeProcess
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern long SymLoadModuleEx(
		//  IntPtr hProcess,
		//  IntPtr hFile,
		//  string ImageName,
		//  string ModuleName,
		//  long BaseOfDll,
		//  int DllSize,
		//  IntPtr /* PMODLOAD_DATA */ Data,
		//  int Flags
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymCleanup(
		//  IntPtr hProcess
		//);

		//[DllImport(DbgHelpDll, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Ansi)]
		//internal static extern bool SymFromAddr(
		//  IntPtr hProcess,
		//  long Address,
		//  out long Displacement,
		//  ref SYMBOL_INFO Symbol
		//);
		//[DllImport(DbgHelpDll, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Ansi)]
		//internal static extern bool SymFromAddr(
		//  IntPtr hProcess,
		//  long Address,
		//  IntPtr Displacement,
		//  IntPtr Symbol
		//);
		//[DllImport(DbgHelpDll, SetLastError = true, ExactSpelling = true)]
		//internal static extern int SymSetOptions(
		//  SymbolOptions SymOptions
		//);
		//[DllImport(DbgHelpDll, SetLastError = true, ExactSpelling = true)]
		//internal static extern SymbolOptions SymGetOptions();
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymGetSearchPath(
		//  IntPtr hProcess,
		//  StringBuilder SearchPath,
		//  int SearchPathLength
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymSetSearchPath(
		//  IntPtr hProcess,
		//  string SearchPath
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymGetSymbolFile(
		//  IntPtr hProcess,
		//  string SymPath,
		//  string ImageFile,
		//  SymbolFileType Type,
		//  StringBuilder SymbolFile,
		//  int cSymbolFile,
		//  StringBuilder DbgFile,
		//  int cDbgFile
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymEnumSymbolsForAddr(
		//  IntPtr hProcess,
		//  long Address,
		//  SymEnumSymbolsProc EnumSymbolsCallback,
		//  IntPtr UserContext
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymEnumSymbols(
		//  IntPtr hProcess,
		//  long BaseOfDll,
		//  string Mask,
		//  SymEnumSymbolsProc EnumSymbolsCallback,
		//  IntPtr UserContext
		//);
		//[DllImport(DbgHelpDll, EntryPoint = "SymEnumSourceFilesW", CharSet = CharSet.Unicode, SetLastError = true)]
		//internal static extern bool SymEnumSourceFiles(
		//  IntPtr hProcess,
		//  long ModBase,
		//  string Mask,
		//  SymEnumSourceFilesProc EnumSymbolsCallback,
		//  IntPtr UserContext
		//);
		//[DllImport(DbgHelpDll, SetLastError = true)]
		//internal static extern bool SymEnumSourceFileTokens(
		//  IntPtr hProcess,
		//  long Base,
		//  SymEnumSourceFileTokensProc Callback
		//);

		//internal delegate bool SymEnumSymbolsProc(
		//  ref SYMBOL_INFO pSymInfo,
		//  long SymbolSize,
		//  IntPtr UserContext
		//);
		//internal delegate bool SymEnumSourceFilesProc(
		//  ref _SOURCEFILE pSourceFile,
		//  IntPtr UserContext
		//);
		//internal delegate bool SymEnumSourceFileTokensProc(
		//    [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
		//    byte[] token,
		//    int size
		//);

		public static string UndecorateSymbolName(
			string decoratedName,
			UndecorateOptions options = 0
			)
		{
			int capacity = 260;
			StringBuilder buffer;
			while (true)
			{
				buffer = new StringBuilder(capacity);
				int resultLength = UnDecorateSymbolName(decoratedName, buffer, capacity, options);
				if (buffer.Length + 50 < capacity) break;
				capacity += 50;
			}
			return buffer.ToString();
		}
	}
}
